From: Keir Fraser Date: Mon, 19 Apr 2010 10:47:59 +0000 (+0100) Subject: stopmachine: Implement using tasklets rather than a softirq. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~12340 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22%22/%22http:/www.example.com/cgi/%22https:/%22%22?a=commitdiff_plain;h=1f437c62318cb6bc81c5f7bbc73a472cc4255a92;p=xen.git stopmachine: Implement using tasklets rather than a softirq. Signed-off-by: Keir Fraser --- diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 93e302f1cc..7e48b66d40 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -2343,6 +2343,10 @@ void machine_halt(void) while(1); } +void sync_local_execstate(void) +{ +} + void sync_vcpu_execstate(struct vcpu *v) { // __ia64_save_fpu(v->arch._thread.fph); diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 07ec8b386d..070810b0af 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -1509,6 +1509,11 @@ int __sync_lazy_execstate(void) return switch_required; } +void sync_local_execstate(void) +{ + (void)__sync_lazy_execstate(); +} + void sync_vcpu_execstate(struct vcpu *v) { if ( cpu_isset(smp_processor_id(), v->vcpu_dirty_cpumask) ) diff --git a/xen/common/stop_machine.c b/xen/common/stop_machine.c index f7d9071b66..99604cde32 100644 --- a/xen/common/stop_machine.c +++ b/xen/common/stop_machine.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -51,6 +51,7 @@ struct stopmachine_data { void *fn_data; }; +static DEFINE_PER_CPU(struct tasklet, stopmachine_tasklet); static struct stopmachine_data stopmachine_data; static DEFINE_SPINLOCK(stopmachine_lock); @@ -81,10 +82,7 @@ int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu) return (*fn)(data); } - /* Note: We shouldn't spin on lock when it's held by others since others - * is expecting this cpus to enter softirq context. Or else deadlock - * is caused. - */ + /* Must not spin here as the holder will expect us to be descheduled. */ if ( !spin_trylock(&stopmachine_lock) ) return -EBUSY; @@ -98,8 +96,9 @@ int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu) smp_wmb(); for_each_cpu_mask ( i, allbutself ) - cpu_raise_softirq(i, STOPMACHINE_SOFTIRQ); + tasklet_schedule_on_cpu(&per_cpu(stopmachine_tasklet, i), i); + sync_local_execstate(); stopmachine_set_state(STOPMACHINE_PREPARE); local_irq_disable(); @@ -118,10 +117,11 @@ int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu) return ret; } -static void stopmachine_softirq(void) +static void stopmachine_action(unsigned long unused) { enum stopmachine_state state = STOPMACHINE_START; + sync_local_execstate(); smp_mb(); while ( state != STOPMACHINE_EXIT ) @@ -153,7 +153,10 @@ static void stopmachine_softirq(void) static int __init cpu_stopmachine_init(void) { - open_softirq(STOPMACHINE_SOFTIRQ, stopmachine_softirq); + unsigned int cpu; + for_each_possible_cpu ( cpu ) + tasklet_init(&per_cpu(stopmachine_tasklet, cpu), + stopmachine_action, 0); return 0; } __initcall(cpu_stopmachine_init); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 3626b98c3a..15f64fc97e 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -480,6 +480,9 @@ void vcpu_sleep_sync(struct vcpu *d); */ void sync_vcpu_execstate(struct vcpu *v); +/* As above, for any lazy state being held on the local CPU. */ +void sync_local_execstate(void); + /* * Called by the scheduler to switch to another VCPU. This function must * call context_saved(@prev) when the local CPU is no longer running in diff --git a/xen/include/xen/softirq.h b/xen/include/xen/softirq.h index 43289cea8d..1408a4cb15 100644 --- a/xen/include/xen/softirq.h +++ b/xen/include/xen/softirq.h @@ -8,7 +8,6 @@ enum { NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ, PAGE_SCRUB_SOFTIRQ, RCU_SOFTIRQ, - STOPMACHINE_SOFTIRQ, NR_COMMON_SOFTIRQS };